import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_ble_ota/ota_callbck.dart';

import 'flutter_ble_ota_platform_interface.dart';

/// An implementation of [FlutterBleOtaPlatform] that uses method channels.
class MethodChannelFlutterBleOta extends FlutterBleOtaPlatform {
  /// The method channel used to interact with the native platform.
  @visibleForTesting
  final methodChannel = const MethodChannel('flutter_ble_ota');
  final EventChannel _eventChannel = const EventChannel("flutter_ble_ota_event");
  BleOtaCallback? _bleOtaCallback;

  MethodChannelFlutterBleOta(){
    methodChannel.setMethodCallHandler((MethodCall call) async {
      if(call.method=="otaStart"){
        _bleOtaCallback?.otaStart?.call();
      }else if(call.method=="otaCancel"){
        _bleOtaCallback?.otaCanceled?.call();
      }else if(call.method=="otaStop"){
        _bleOtaCallback?.otaStop?.call();
      }
    });
  }

  @override
  Future<String?> getPlatformVersion() async {
    final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
    return version;
  }

  @override
  Future<bool> startOTA(String filePath,{BleOtaCallback? callback}) async {
    _bleOtaCallback = callback;
    _eventChannel.receiveBroadcastStream().listen((e){
      if(e.containsKey("status")){
        int status = e["status"]??0;
        if(status==1){
          if(e.containsKey("type") && e.containsKey("progress")){
            _bleOtaCallback?.otaProgress?.call(e["type"]??-1,e["progress"]??0.0);
          }
        }else if(status==2){
          if(e.containsKey("code") && e.containsKey("msg")){
            _bleOtaCallback?.otaError?.call(e["code"]??-1,e["msg"]??"unknown");
          }
        }
      }

    }, onError: (code,msg){

    });
    return await methodChannel.invokeMethod('startOTA',filePath);
  }

  @override
  Future<bool> connect(String address) async {
    return await methodChannel.invokeMethod('connectDevice',address);
  }

  @override
  Future<bool> initOTA() async {
    return await methodChannel.invokeMethod('initOTA');
  }

  @override
  Future<bool> dispose() async {
    _bleOtaCallback = null;
    return await methodChannel.invokeMethod('dispose');
  }
}
